home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / misc / db3.6-beta / db3.6-beta-src / dbgui.c < prev    next >
C/C++ Source or Header  |  1999-11-30  |  48KB  |  1,113 lines

  1. /*
  2.  *  GUI Designed by : David Ekholm, Datadosen
  3.  */
  4.  
  5. #include <stdlib.h>     /* atoi() */
  6. #include <exec/types.h>
  7. #include <exec/memory.h>
  8. #include <intuition/intuition.h>
  9. #include <intuition/intuitionbase.h>
  10. #include <intuition/screens.h>  /* DrawInfo */
  11. #include <intuition/classes.h>
  12. #include <intuition/classusr.h>
  13. #include <intuition/imageclass.h>
  14. #include <intuition/gadgetclass.h>
  15. #include <gadgets/textfield.h>
  16.  
  17. #include <intuition/sghooks.h> /* struct SGWork here */
  18. #include <workbench/workbench.h>        /* For AppWindow */
  19. #include <libraries/gadtools.h>
  20. #include <libraries/commodities.h> /* This has a nice qualifier #define */
  21. #include <libraries/iffparse.h>
  22.  
  23. #include <graphics/displayinfo.h>
  24. #include <graphics/gfxbase.h>
  25. #include <graphics/text.h>              /* For my TextAttr struct */
  26. #include <graphics/rastport.h>
  27. #include <utility/hooks.h>              /* For my stringhook */
  28.  
  29. #include <proto/wb.h>                           /* For AppWindow */
  30. #include <clib/exec_protos.h>
  31. #include <clib/intuition_protos.h>
  32. #include <clib/gadtools_protos.h>
  33. #include <clib/graphics_protos.h>
  34. #include <clib/utility_protos.h>
  35. #include <string.h>
  36. #include <pragmas/exec_pragmas.h>
  37. #include <pragmas/intuition_pragmas.h>
  38. #include <pragmas/gadtools_pragmas.h>
  39. #include <pragmas/graphics_pragmas.h>
  40. #include <pragmas/utility_pragmas.h>
  41. #include <proto/textfield.h>
  42.  
  43. #include "dbGUI.h"
  44. #include "db.h"
  45. #include "dbparser.h"
  46. #include "Version.h"
  47.  
  48.  
  49. #define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2
  50.  
  51. extern Class *TextFieldClass;
  52. extern struct IFFHandle *Iff0;
  53.  
  54. struct Screen         *Scr = NULL;
  55. struct DrawInfo *DrInfo = NULL;
  56. UWORD *Pens;
  57. APTR                   VisualInfo = NULL;
  58. struct IntuiMessage    DB_Msg;
  59. UWORD                  DB_Zoom[4];
  60. struct Gadget          *LastGad = NULL;
  61. struct Hook                                     MyStrHook;
  62. struct TextAttr       *Font, Attr;
  63. UWORD                  FontX, FontY;
  64. UWORD                  OffX, OffY;
  65. UWORD                  DragKnobWidth, DragKnobHeight;
  66.  
  67. WORD LastLeftEdge=-1;
  68. WORD LastTopEdge=-1;                                    /* For nice layoutswitching */
  69.  
  70. /*For gadgetlayout */
  71. UWORD TabSize;
  72.  
  73. /* For MyStrHookFunc() */
  74. BOOL ReactivateGad = FALSE;
  75. BOOL GadDoubleClicked = FALSE;
  76. struct Gadget *NextGad = NULL;
  77.  
  78. struct TextAttr UserTextAttr =
  79. {
  80.         NULL, 0, FS_NORMAL, FPF_DISKFONT
  81. };
  82.  
  83.  
  84. struct NewMenu DB_NewMenu[] = {
  85.         NM_TITLE, (STRPTR)MSG_PROJECT_MENU , NULL, 0, NULL, NULL,
  86.         NM_ITEM, (STRPTR)MSG_PROJECT_NEW   , NULL, 0, 0L,   (APTR)DB_NEW,
  87.         NM_ITEM, (STRPTR)MSG_PROJECT_OPEN  , NULL, 0, 0L,   (APTR)DB_OPEN,
  88.         NM_ITEM, (STRPTR)MSG_PROJECT_RELOAD, NULL, 0, 0L,   (APTR)DB_RELOAD,
  89.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  90.         NM_ITEM, (STRPTR)MSG_PROJECT_SAVE   , NULL, 0, 0L,  (APTR)DB_SAVE,
  91.         NM_ITEM, (STRPTR)MSG_PROJECT_SAVE_AS, NULL, 0, 0L,  (APTR)DB_SAVEAS,
  92.         NM_ITEM, (STRPTR)MSG_PROJECT_OUTPUT , NULL, 0, NULL,NULL,
  93.         NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW,
  94.         NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW_WN, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW_WN,
  95.         NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_TAB_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_TAB_ASCII,
  96.         NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_COMMA_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_COMMA_ASCII,
  97.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  98.         NM_ITEM, (STRPTR)MSG_PROJECT_ABOUT, NULL, 0, 0L, (APTR)DB_ABOUT,
  99.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  100.         NM_ITEM, (STRPTR)MSG_PROJECT_QUIT, NULL, 0, 0L, (APTR)DB_QUIT,
  101.         NM_TITLE, (STRPTR)MSG_EDIT_MENU, NULL, 0, NULL, NULL,
  102.         NM_ITEM, (STRPTR)MSG_EDIT_CUT, NULL, 0, 0L, (APTR)DB_CUT,
  103.         NM_ITEM, (STRPTR)MSG_EDIT_COPY, NULL, 0, 0L, (APTR)DB_COPY,
  104.         NM_ITEM, (STRPTR)MSG_EDIT_PASTE, NULL, 0, 0L, (APTR)DB_PASTE,
  105.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  106.         NM_ITEM, (STRPTR)MSG_EDIT_ADD, NULL, 0, 0L, (APTR)DB_ADD,
  107.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  108.         NM_ITEM, (STRPTR)MSG_EDIT_KILL, NULL, 0, 0L, (APTR)DB_KILL,
  109.         NM_TITLE, (STRPTR)MSG_VIEW_MENU, NULL, 0, NULL, NULL,
  110.         NM_TITLE, (STRPTR)MSG_ACTION_MENU, NULL, 0, NULL, NULL,
  111.         NM_ITEM, (STRPTR)MSG_ACTION_FIND, NULL, 0, 0L, (APTR)DB_FIND,
  112.         NM_ITEM, (STRPTR)MSG_ACTION_FIND_NEXT, NULL, 0, 0L, (APTR)DB_FINDNEXT,
  113.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  114.         NM_ITEM, (STRPTR)MSG_ACTION_SORT, NULL, 0, 0L, (APTR)DB_SORT,
  115.         NM_ITEM, (STRPTR)MSG_ACTION_DIAL, NULL, 0, 0L, (APTR)DB_DIAL,
  116.         NM_ITEM, (STRPTR)MSG_ACTION_BROWSE, NULL, 0, 0L, (APTR)DB_BROWSE,
  117.         NM_TITLE, (STRPTR)MSG_SETTINGS_MENU, NULL, 0, NULL, NULL,
  118.         NM_ITEM, (STRPTR)MSG_SETTINGS_WARNINGS, NULL, CHECKIT|CHECKED|MENUTOGGLE, 0L, (APTR)DB_WARNINGS,
  119.         NM_ITEM, (STRPTR)MSG_SETTINGS_SORTDIR, NULL, 0, NULL, NULL,
  120.         NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_AZ, NULL, CHECKIT|CHECKED, 2L, (APTR)DB_AZ,
  121.         NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_ZA, NULL, CHECKIT, 1L, (APTR)DB_ZA,
  122.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  123.         NM_ITEM, (STRPTR)MSG_SETTINGS_FIELD_DEFINITION, NULL, NM_ITEMDISABLED, 0L, (APTR)DB_FIELD_DEFINITION,
  124.         NM_ITEM, (STRPTR)MSG_SETTINGS_VIEW_DESIGN, NULL, 0L, 0L, (APTR)DB_VIEW_DESIGN,
  125.         NM_TITLE, (STRPTR)MSG_AREXX_MENU, NULL, 0, NULL, NULL,
  126.         NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX,
  127.         NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE_RELAUNCH, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX_AGAIN,
  128.         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
  129.         NM_END, NULL, NULL, 0, 0L, NULL };
  130.  
  131.  
  132. void LocalizeMenu(struct NewMenu *nm)
  133. {
  134.         /* Replaces the string-indexes in the NewMenu array with localized text */
  135.         /* Gets called once from SetupScreen() */
  136.         UWORD   i=0;
  137.  
  138.         while (nm[i].nm_Type != NM_END) {
  139.                 if (nm[i].nm_Label != NM_BARLABEL) {
  140.                         nm[i].nm_CommKey = GetAppStr((LONG)nm[i].nm_Label);
  141.  
  142.                         nm[i].nm_Label = nm[i].nm_CommKey+2;
  143.                         if (nm[i].nm_CommKey[0] == ' ') nm[i].nm_CommKey = NULL;
  144.                 }
  145.         ++i;
  146.         }
  147. }
  148. /**/
  149. __inline BOOL OkStrGad(struct Gadget *g)
  150. {
  151.         return (BOOL)(g->Flags & GFLG_TABCYCLE && !(g->Flags & GFLG_DISABLED));
  152. }
  153.  
  154. struct Gadget *PrevStrGad(struct Gadget *Gad, struct Gadget *glist)
  155. {
  156.         /* Returns the previous stringgadget, or NULL if Gad is the first one */
  157.  
  158.         struct Gadget *strgad = NULL, *g = glist;
  159.  
  160.         if (g == Gad) return NULL;
  161.         for (; g; g = g->NextGadget) {
  162.                 if (OkStrGad(g)) strgad = g;    /* Only return stringgads */
  163.                 if (g->NextGadget == Gad) break;
  164.         }
  165.         return strgad;
  166. }
  167.  
  168. struct Gadget *EndGad(struct Gadget *g)
  169. {
  170.         while (g->NextGadget) g = g->NextGadget;
  171.         return g;
  172. }
  173.  
  174. struct Gadget *ActivateThisGad(ULONG actions, struct Gadget *current,
  175.  struct Gadget *glist)
  176. {
  177.         /* Takes over the job of deciding which (if any) gadget should be reactivated
  178.          * based upon the SGWork->Actionfield.
  179.          * Without this function, it is impossible to activate other stringgadgets
  180.          * (as responce to an ARexx command) as Intiuition otherwize will have
  181.          * activated some other gadget first if the user cyclesteps thru a gadgetlist.
  182.     */
  183.         struct Gadget *g = NULL;
  184.  
  185.         if (actions & SGA_NEXTACTIVE) {
  186.                 for (g = current->NextGadget;; g = g->NextGadget) {
  187.                         if (!g) g = glist;
  188.                         if (OkStrGad(g)) break;
  189.                 }
  190.         }
  191.         else if (actions & SGA_PREVACTIVE) {
  192.                 for (g = PrevStrGad(current, glist);; g = PrevStrGad(g, glist)) {
  193.                         if (!g) g = EndGad(glist);
  194.                         if (OkStrGad(g)) break;
  195.                 }
  196.         }
  197.         return g;
  198. }
  199.  
  200.  
  201. /* Stuff for my stringHook */
  202.  
  203. ULONG __saveds __asm MyStrHookFunc(register __a0 struct Hook *hook,
  204.                                                                                           register __a2 struct SGWork *sgw,
  205.                                                                                           register __a1 ULONG *msg)
  206. {
  207.         /* This hook does the following modifications to a gadtool stringgadet:
  208.          * Pressing ESC will terminate the gadget without leaving the ESC char.
  209.          * Pressing R-Amiga+Key will terminate the gadget leaving the keycode in
  210.          * the Code field of the GadgetUp IDCMP event that will follow. It will
  211.     * also reuse the inputevent, making Intition select the corresponding menu.
  212.          * Pressing up, down, shift-up or shift-down will navigate between records.
  213.          * It also responds to the keys F1 to F10.
  214.          * Doubleclicking into a stringgadget will invoke a special function
  215.          */
  216.  
  217.         static ULONG StartSecs=0, StartMicros=0;
  218.         ULONG CurrentSecs, CurrentMicros;
  219.         ULONG return_code = ~0;
  220.  
  221.         if (*msg == SGH_KEY) {  /* Process some key event */
  222.                 if ((sgw->EditOp == EO_REPLACECHAR) || (sgw->EditOp == EO_INSERTCHAR)) {
  223.                         /* sgw->Code is VANILLAKEY, sgw->IEvent->ie_Code is RAWKEY */
  224.  
  225.                         if (sgw->IEvent->ie_Code == RAW_ESC)    {       /* ESC pressed */
  226.                                 sgw->Actions &= ~SGA_USE;       /* ~SGA_BEEP will not prevent beep :-( */
  227.                                 sgw->Actions |=  SGA_END;       /* NewEdit does this */
  228.                         }
  229.                         else if (sgw->IEvent->ie_Qualifier &
  230.                          (IEQUALIFIER_RCOMMAND | IEQUALIFIER_LCOMMAND)) {
  231.                                 sgw->Actions &= ~SGA_USE;
  232.                                 sgw->Actions |=  SGA_END | SGA_REUSE;
  233. /**/                    ReactivateGad = TRUE;
  234.                         }
  235.                 }
  236.                 else if (sgw->EditOp == EO_ENTER && sgw->Code != RAW_HELP) {
  237.                         if (!(MyArgArray[NORETURNSTEP] ||
  238.                          sgw->IEvent->ie_Qualifier & IXSYM_ALTMASK)) {
  239.                                 if (sgw->IEvent->ie_Qualifier & IXSYM_SHIFTMASK) 
  240.                                         sgw->Actions |= SGA_PREVACTIVE;
  241.                                 else sgw->Actions |= SGA_NEXTACTIVE;
  242.                         }
  243.                 }
  244.                 else if (sgw->EditOp == EO_NOOP) {
  245.                         if (sgw->IEvent->ie_Code == RAW_DOWN || sgw->IEvent->ie_Code == RAW_UP) {
  246.                                 /* Down or up key pressed */
  247.                                 sgw->Actions &= ~SGA_USE;
  248.                                 sgw->Actions |=  SGA_END | SGA_REUSE;
  249.                                 ReactivateGad = TRUE;
  250.                         }
  251.                         else if (sgw->IEvent->ie_Code == RAW_ESC)       {       /* ESC pressed */
  252.                                 sgw->Actions &= ~SGA_USE;       /* ~SGA_BEEP will not prevent beep :-( */
  253.                                 sgw->Actions |=  SGA_END;       /* NewEdit does this */
  254.                         }
  255.                         else if (sgw->IEvent->ie_Code >= RAW_F1 && sgw->IEvent->ie_Code <= RAW_F10) {
  256.                                 sgw->Actions &= ~SGA_USE;
  257.                                 sgw->Actions |=  SGA_END | SGA_REUSE;
  258.                         }
  259.                 }
  260.                 if (sgw->Actions & SGA_END) {
  261.                         if (NextGad = ActivateThisGad(sgw->Actions, sgw->Gadget,
  262.                          sgw->GadgetInfo->gi_Window->FirstGadget))
  263.                                 sgw->Actions &= ~(SGA_PREVACTIVE | SGA_NEXTACTIVE);
  264.                 }
  265.         }
  266.         else if (*msg == SGH_CLICK) {                                   /* Process mouse click */
  267.                 CurrentSecs = sgw->IEvent->ie_TimeStamp.tv_secs;
  268.                 CurrentMicros = sgw->IEvent->ie_TimeStamp.tv_micro;
  269.                 
  270.                 if (DoubleClick(StartSecs, StartMicros, CurrentSecs, CurrentMicros)
  271.                  && sgw->BufferPos == sgw->StringInfo->BufferPos) {
  272.                         /* Only allow doubleclick if user doubleclicks at the same character */
  273.                         /* to avoid accidental doubleclick if user only wants to position */
  274.                         /* cursor exactly */
  275.                         GadDoubleClicked = TRUE;
  276.  
  277.                         StartSecs = StartMicros = 0;    /* Prevent "triple clicks" */
  278.                 }
  279.                 else {
  280.                         StartSecs = CurrentSecs;
  281.                         StartMicros = CurrentMicros;
  282.                 }
  283.         }
  284.         else return_code = 0;
  285.  
  286.         return return_code;
  287. }
  288.  
  289.  
  290. void InitHook(struct Hook *hook)
  291. {
  292.         hook->h_Entry = (HOOKFUNC)MyStrHookFunc;
  293.         hook->h_SubEntry = NULL;
  294.         hook->h_Data = 0;
  295. }
  296.  
  297.  
  298. int SetupScreen( void )
  299. {
  300. /*
  301.         struct Screen *s;
  302.         if (!Stricmp(MyArgArray[PUBSCREEN] "frontmost")) {
  303.                 for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
  304.                         if (s->Flags & PUBLICSCREEN) 
  305.         }
  306.         else {
  307. */
  308.                 if (!(Scr = LockPubScreen((STRPTR)MyArgArray[PUBSCREEN])))
  309.                         if (!(Scr = LockPubScreen(NULL)))       /* Workbench */
  310.                                 return( 1L );
  311. /*      } */
  312.  
  313.         if ( ! ( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
  314.                 return( 2L );
  315.  
  316.         if ( ! (DrInfo = GetScreenDrawInfo(Scr)))
  317.                 return 3L;
  318.         Pens = DrInfo->dri_Pens;
  319.  
  320.  
  321.         LocalizeMenu(DB_NewMenu);
  322.         LocalizeMenu(DesignNewMenu);
  323.  
  324.         InitHook(&MyStrHook);
  325.  
  326.         return( 0L );
  327. }
  328.  
  329. void CloseDownScreen( void )
  330. {
  331.         if (DrInfo) FreeScreenDrawInfo(Scr, DrInfo);
  332.         if ( VisualInfo ) {
  333.                 FreeVisualInfo( VisualInfo );
  334.                 VisualInfo = NULL;
  335.         }
  336.  
  337.         if ( Scr        ) {
  338.                 UnlockPubScreen( NULL, Scr );
  339.                 Scr = NULL;
  340.         }
  341. }
  342.  
  343.  
  344. int HandleDB_IDCMP(struct Layout *Lay)
  345. {
  346.         struct IntuiMessage     *m;
  347.         struct MenuItem         *n;
  348.         int                     (*func)(void);
  349.         struct Window *Win = Lay->Window;
  350.         struct VisFldInfo *vf;
  351.  
  352.         BOOL running = TRUE;
  353.  
  354.         while( m = GT_GetIMsg( Win->UserPort )) {
  355.  
  356.                 CopyMem(( char * )m, ( char * )&DB_Msg, (long)sizeof( struct IntuiMessage ));
  357.  
  358.                 GT_ReplyIMsg( m );
  359.                 
  360.                 switch ( DB_Msg.Class ) {
  361.                 
  362.                         case IDCMP_INTUITICKS:
  363.                                 if (GadDoubleClicked) {
  364.                                         running = DB_SpecialAction(TRUE);
  365.                                         GadDoubleClicked = FALSE;
  366.                                 }
  367.                                 break;
  368.  
  369.                         case    IDCMP_REFRESHWINDOW:
  370.                                 GT_BeginRefresh(Win);
  371.                                 GT_EndRefresh(Win, TRUE );
  372.                                 break;
  373.  
  374.                         case    IDCMP_CLOSEWINDOW:
  375.                                 running = DB_CloseWindow();
  376.                                 break;
  377.  
  378.                         case    IDCMP_MENUHELP:
  379.                                 running = DB_MenuHelp();
  380.                                 break;
  381.  
  382.                         case    IDCMP_NEWSIZE:
  383.                                 running = DB_NewSize();
  384.                                 break;
  385.  
  386.                         case    IDCMP_VANILLAKEY:
  387.                                 if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
  388.                                         running = DB_VanillaKey();
  389.                                 break;
  390.  
  391.                         case    IDCMP_RAWKEY:
  392.                                 if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
  393.                                         running = DB_RawKey();
  394.                                         if (running) return running;    /* The window has been closed! */
  395.                                 break;
  396.  
  397.                         case    IDCMP_GADGETUP:
  398.                                 {
  399.                                         struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
  400.                                         if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
  401.                                         else {
  402.                                                 if ((gad->GadgetID == CHECKBOX_KIND) ||
  403.                                                          (gad->GadgetID == CYCLE_KIND)) {
  404.                                                         LastGad = gad;
  405.                                                         VisFldSelected(gad);
  406.                                                         vf = GetVisFldInfo(Lay, gad);
  407.                                                         vf->Code = DB_Msg.Code;
  408.                                                 }
  409.                                                 if (!ReactivateGad)
  410.                                                         running = DB_SpecialAction(FALSE);
  411.                                                 if (NextGad) ActivateGadget(NextGad, Win, NULL);
  412.                                         }
  413.                                 }
  414.                                 break;
  415.  
  416.                         case    IDCMP_GADGETDOWN:
  417.                                 {
  418.                                         struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
  419.  
  420.                                         if (gad->GadgetID == STRING_KIND || gad->GadgetID == TEXTFIELD_KIND) {
  421.                                                 LastGad = gad;
  422.                                                 VisFldSelected(gad);
  423.                                         }
  424.                                         else if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
  425.                                 }
  426.                                 break;
  427.  
  428.                         case    IDCMP_MENUPICK:
  429.                                 while( DB_Msg.Code != MENUNULL ) {
  430.                                         n = ItemAddress( Win->MenuStrip, DB_Msg.Code );
  431.                                         func = (int (*)(void))(GTMENUITEM_USERDATA( n ));
  432.                                         running = func();
  433.                                         if (running) return running;    /* The window has been closed! */
  434.                                         DB_Msg.Code = n->NextSelect;
  435.                                 }
  436.                                 break;
  437.  
  438.                         /* Added by me as GadToolBox won't do that */
  439.                         case    IDCMP_MOUSEMOVE:
  440.                                 DB_MouseMove();
  441.                                 break;
  442.                 }
  443.         }
  444.         if (ReactivateGad) ReactivateGad = FALSE;
  445.         return( running );
  446. }
  447.  
  448. void DeleteSoftMenu(struct SoftMenu *sm)
  449. {
  450.         if (sm->Items) FreeMenus((struct Menu *)sm->Items);
  451.         sm->Items = NULL;
  452.         if (sm->NewItems) FreeMem(sm->NewItems, sm->NewItemsNum * sizeof(struct NewMenu));
  453.         sm->NewItems = NULL;
  454.         sm->NewItemsNum = 0;
  455. }
  456.  
  457. void CloseMenu(struct Pro *Pr)
  458. {
  459.         /* Frees all memory allocated by OpenMenu() */
  460.  
  461.         if (Pr->Menu) FreeMenus(Pr->Menu);
  462.         Pr->Menu = NULL;
  463.         DeleteSoftMenu(&Pr->ViewMenu);
  464.         DeleteSoftMenu(&Pr->ARexxMenu);
  465. }
  466.  
  467. int AddViewMenu(struct Pro *Pr)
  468. {
  469.         int n;
  470.         struct Layout *Lay;
  471.  
  472.         /* Count how many layouts there are */
  473.         for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++);
  474.         if (!n) return 0;       /* No layouts at all. Extra safety */
  475.  
  476.         Pr->ViewMenu.NewItemsNum = n+1; /* One extra array-closing item */
  477.         /* Allocate memory for the NewMenu structs */
  478.         if (!(Pr->ViewMenu.NewItems =
  479.          AllocMem(Pr->ViewMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
  480.  
  481.         /* Fill in the NewMenu structs */
  482.         for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++) {
  483.                 Pr->ViewMenu.NewItems[n].nm_Type = NM_ITEM;
  484.                 Pr->ViewMenu.NewItems[n].nm_Label = (STRPTR)Lay->Name;
  485.                 Pr->ViewMenu.NewItems[n].nm_Flags = CHECKIT;
  486.                 Pr->ViewMenu.NewItems[n].nm_MutualExclude = ~(1<<n);
  487.                 Pr->ViewMenu.NewItems[n].nm_UserData = (APTR)DB_VIEW;
  488.         }
  489.         Pr->ViewMenu.NewItems[n].nm_Type = NM_END;
  490.         Pr->ViewMenu.NewItems[0].nm_Flags |= CHECKED;
  491.  
  492.         if (!(Pr->ViewMenu.Items = (struct MenuItem *)CreateMenus(Pr->ViewMenu.NewItems, TAG_DONE))) return MENU_ERR;
  493.         Pr->Menu->NextMenu->NextMenu->FirstItem = Pr->ViewMenu.Items;   /* Link in */
  494.         return 0;       /* ok */
  495. }
  496.  
  497. int AddARexxMenu(struct Pro *Pr)
  498. {
  499.         int n;
  500.         struct RxInfo *ri;
  501.         struct RFFTag *tag;
  502.         char *label;
  503.  
  504.         /* Count how many ARexx items there are */
  505.         for (n=0, ri=Pr->FirstRxInfo; ri; ri=ri->Next, n++);
  506.         if (n < 2) return 0;    /* No ARexx menu items at all (The global RFF data is in the first node). */
  507.  
  508.         Pr->ARexxMenu.NewItemsNum = n;  /* One extra array-closing item */
  509.         /* Allocate memory for the NewMenu structs */
  510.         if (!(Pr->ARexxMenu.NewItems =
  511.          AllocMem(Pr->ARexxMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;
  512.  
  513.         /* Fill in the NewMenu structs */
  514.         for (n=0, ri=Pr->FirstRxInfo->Next; ri; ri=ri->Next, n++) {
  515.                 Pr->ARexxMenu.NewItems[n].nm_Type = NM_ITEM;
  516.                 if (!(tag = FindTag(&ri->RxTags, NAME)) && !(tag = FindTag(&ri->RxTags, RXFILE)))
  517.                         label = "« error »";
  518.                 else label = tag->Data;
  519.                 Pr->ARexxMenu.NewItems[n].nm_Label = (STRPTR)label;
  520.                 Pr->ARexxMenu.NewItems[n].nm_UserData = (APTR)DB_AREXX;
  521.         }
  522.         Pr->ARexxMenu.NewItems[n].nm_Type = NM_END;
  523.  
  524.         if (!(Pr->ARexxMenu.Items = (struct MenuItem *)CreateMenus(Pr->ARexxMenu.NewItems, TAG_DONE))) return MENU_ERR;
  525.         Pr->Menu->NextMenu->NextMenu->NextMenu->NextMenu->NextMenu->
  526.         FirstItem->NextItem->NextItem->NextItem = Pr->ARexxMenu.Items;    /* Link in */
  527.         return 0;       /* ok */
  528. }
  529.  
  530. int OpenMenu(struct Pro *Pr)
  531. {
  532.         /* Builds a complete menu including the variable View menu */
  533.         int err;
  534.  
  535.         if (!(Pr->Menu = CreateMenus(DB_NewMenu, TAG_DONE))) return MENU_ERR;
  536.  
  537.         if (err = AddViewMenu(Pr)) {
  538.                 CloseMenu(Pr);
  539.                 return err;
  540.         }
  541.         if (err = AddARexxMenu(Pr)) {
  542.                 CloseMenu(Pr);
  543.                 return err;
  544.         }
  545.         LayoutMenus(Pr->Menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE );
  546.         return 0;
  547. }
  548.  
  549. void GadSpace(struct VisFldInfo *vf, struct RastPort *rp)
  550. {
  551.         /* Calculate the offset and size of a vf info vf->Pos. */
  552.    /* Take space for the gadgets name into account */
  553.         /* If rp is NULL then topaz 8 is assumed */
  554.  
  555.         int len;
  556.         char *buffer, *bufp, *namep;
  557.         int diff, rows;
  558.         struct RFFTag *tag;
  559.  
  560.         vf->Pos.YOffset = vf->Pos.XOffset = 0;
  561.         vf->Label.LeftEdge = vf->Label.TopEdge = 0;     /* textfield gadget */
  562.         
  563.         tag = SearchTag(CurrentPro, vf, NULL, PLACE);
  564.         if (tag && !Stricmp(tag->Data, "above")) {              /* Title is above gadget */
  565.                 vf->Pos.YOffset = FontY + (FontY >> 1); /* Seems to look nice */
  566.                 vf->Label.TopEdge = -vf->Pos.YOffset;           /* textfield gadget */
  567.         }
  568.         else {  /* Title is to the left of gadget */
  569.                 /* gadgetname size */
  570.                 len = strlen(vf->Name);
  571.                 if (!(buffer = AllocMem(len+1,0))) return;      /* mem fail */
  572.  
  573.                 /* Strip underscore _ in gadetname for correct length */
  574.                 for (bufp = buffer, namep = vf->Name;; namep++) {
  575.                         if (*namep != '_') *bufp++ = *namep;
  576.                         if (!(*namep)) break;   /* Also copy the \0 char */
  577.                 }
  578.                 if (rp) vf->Pos.XOffset = TextLength(rp,buffer,strlen(buffer));
  579.                 else vf->Pos.XOffset = FontX * strlen(buffer);  /* Topaz 8 */
  580.                 FreeMem(buffer, len+1);
  581.                 if (vf->Pos.XOffset) vf->Pos.XOffset += FontX;                  /* If vf->name, add extra space */
  582.                 vf->Label.LeftEdge = -vf->Pos.XOffset;  /* textfield gadget */
  583.         }
  584.  
  585.         vf->Pos.Width = FontX * (vf->VisLen + 2);
  586.         diff = vf->Pos.XOffset % FontX;
  587.         if (diff) vf->Pos.XOffset += FontX - diff;              /* Snap to next FontX tick */
  588.  
  589.         tag = SearchTag(CurrentPro, vf, NULL, ROWS);
  590.         if (tag && (rows = atoi(tag->Data))) {
  591.                 vf->Pos.Height = FontY * rows + STRGADFRAMESHEIGHT;
  592.         }
  593.         else vf->Pos.Height = FontY + STRGADFRAMESHEIGHT;
  594. }
  595.  
  596.  
  597. __inline WORD LineOffset(struct VisFldInfo *vf)
  598. {
  599.         /* Return the maximum Y offset needed for a line of visual fields */
  600.         WORD oldmax = 0;
  601.         
  602.         for (; vf; vf = vf->Next) {
  603.                 if (vf->Pos.YOffset > oldmax) oldmax = vf->Pos.YOffset;
  604.                 if (vf->VisSep == '\n' || vf->VisSep == '\f') break;
  605.         }
  606.         return oldmax;
  607. }
  608.  
  609. __inline BOOL EndOfLine(struct VisFldInfo *vf)
  610. {
  611.         return (BOOL)(vf->VisSep == '\n' || vf->VisSep == '\f' || !vf->Next);
  612. }
  613.  
  614. BOOL CalcPos(struct Layout *Lay, struct Space *GLim, WORD *ww, WORD *wh,
  615.  struct RastPort *rp)
  616. {
  617.         struct VisFldInfo *vf;
  618.         WORD curX = 0, curY = 0;
  619.         BOOL firstCol = TRUE;
  620.         int stepsize = 0;
  621.         WORD maxheight = 0;
  622.         
  623.         GLim->XOffset = GLim->Width = GLim->YOffset = GLim->Height = 0;
  624.  
  625.         /* First set each vf's local offset and size */
  626.         for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next)
  627.                 GadSpace(vf, rp);
  628.  
  629.         /* Now adjust all vf's according to one another */
  630.         for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  631.  
  632.                 if (firstCol) {
  633.                         curY += LineOffset(vf); /* This line's max Y offset */
  634.                         if (vf->Pos.XOffset > GLim->XOffset) GLim->XOffset = vf->Pos.XOffset;
  635.                         vf->Pos.XOffset = 0;            /* It will be added later */
  636.                 }
  637.                 vf->Pos.XOffset += curX;
  638.                 vf->Pos.YOffset = curY;
  639.  
  640.                 if (stepsize) {
  641.                         vf->Pos.XOffset += stepsize - vf->Pos.XOffset % stepsize;
  642.                         stepsize = 0;
  643.                 }
  644.  
  645.                 if (vf->Pos.XOffset + vf->Pos.Width > GLim->Width)
  646.                         GLim->Width = vf->Pos.XOffset + vf->Pos.Width;
  647.                 
  648.                 if (vf->Pos.Height > maxheight) maxheight = vf->Pos.Height;
  649.  
  650.                 if (EndOfLine(vf)) {
  651.                         firstCol = TRUE;
  652.                         curX = 0;
  653.                         curY += maxheight;
  654.                         GLim->Height = curY;
  655.                         maxheight = 0;  
  656.                 }
  657.                 switch (vf->VisSep) {
  658.                         case ' ':
  659.                                 curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
  660.                                 firstCol = FALSE;
  661.                                 stepsize = 0;
  662.                                 break;
  663.                         case '\t':
  664.                                 curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
  665.                                 stepsize = TabSize * FontX;
  666.                                 firstCol = FALSE;
  667.                                 break;
  668.                         case '\f':
  669.                                 curY += (FontY * 3 >> 1);       /* Looks nice */
  670.                                 break;
  671.                         case '\n':
  672.                         default:
  673.                                 curY += (FontY * 3 >> 3); /* Looks nice */
  674.                                 break;
  675.                 }
  676.         }
  677.         GLim->Width += GLim->XOffset;
  678.         *ww = OffX + (FontX << 1) + GLim->Width + Scr->WBorRight;
  679.         *wh = OffY + FontY + GLim->Height + Scr->WBorBottom;
  680.         if (MyArgArray[HORIZBAR]) *wh += DragKnobHeight;
  681.         else *ww += DragKnobWidth;
  682.  
  683.         return TRUE;
  684. }
  685.  
  686. void DeleteAllGadgets(struct Layout *Lay, char mode)
  687. {
  688.         struct VisFldInfo *vf;
  689.         struct Gadget *g;
  690.  
  691.         /* Relink the gadgetborders we deleted for sake of speed */
  692.         if (mode == USE_MODE && Lay->FirstSR) SpeedRenderOff(Lay);      /* FirstSR will be cleared */
  693.  
  694.         if (Lay->GList) {
  695.                 if (mode == USE_MODE && Lay->Window) RemoveGList(Lay->Window, Lay->GList, -1);
  696.  
  697.                 /* Remove objects first */
  698.                 for (g = Lay->GList; g && g->NextGadget; g = g->NextGadget) {
  699.                         if (g->NextGadget->GadgetID == TEXTFIELD_KIND) {
  700.                                 DisposeObject(g->NextGadget);
  701.                                 g->NextGadget = g->NextGadget->NextGadget;      /* Objects shall not be freed by FreeGadgets */
  702.                         }
  703.                 }
  704.                 FreeGadgets(Lay->GList);
  705.                 Lay->GList = NULL;
  706.         }
  707.         for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  708.                 vf->Gadget = NULL;
  709.                 vf->Code = 0;
  710.         }
  711.         LastGad = NULL;
  712. }
  713.  
  714. void CloseLayWin(struct Pro *Pr, struct Layout *Lay)
  715. {
  716.         CloseSelect(CurrentPro->CurrentLayout->Browser);
  717.         RemoveAllStrings(CurrentPro->CurrentLayout->Browser);
  718.  
  719.         DeleteAllGadgets(Lay, USE_MODE);
  720.         if (Lay->Window) {
  721.                 /* Remember old window pos */
  722.                 LastLeftEdge = Lay->Window->LeftEdge;
  723.                 LastTopEdge = Lay->Window->TopEdge;
  724.                 /* AppWindow specifics */
  725.                 if (Lay->AppWin) RemoveAppWindow(Lay->AppWin);
  726.                 Lay->AppWin = NULL;
  727.                 ClearMenuStrip(Lay->Window);
  728.                 CloseWindow(Lay->Window);
  729.                 Lay->Window = NULL;
  730.         }
  731. }
  732.  
  733. void AdjustVars(struct RastPort *rp)
  734. {
  735.         /* Supportfunction to simplify OpenLayWin */
  736.         if (rp) {
  737.                 Font->ta_Name = (STRPTR)rp->Font->tf_Message.mn_Node.ln_Name;
  738.                 Font->ta_YSize = FontY = rp->Font->tf_YSize;
  739.                 FontX = rp->Font->tf_XSize;
  740.         }
  741.         else {
  742.                 Font->ta_Name = (STRPTR)"topaz.font";
  743.                 FontX = FontY = Font->ta_YSize = 8;
  744.         }
  745.         DragKnobHeight = FontY;
  746.         if (DragKnobHeight < 12) DragKnobHeight = 12;
  747.         DragKnobWidth = (DragKnobHeight * 5) >> 2;
  748. }
  749.  
  750. int CalcAllPos(struct Pro *Pr, struct Layout *Lay, WORD *ww, WORD *wh)
  751. {
  752.         /* Calculate the position of all gadgets and put the final windowsize in ww and wh */
  753.         struct RastPort *rp = &Scr->RastPort, *myrp=NULL;
  754.         struct RFFTag *tag;
  755.         struct Space GLim;      /* "rectangle" that gadgets are to be drawn within */
  756.         struct VisFldInfo *vf;
  757.  
  758.         if (UserTextFont) {
  759.                 /* Alloc and init a dummy RastPort for TextLength() with custom fonts */
  760.                 if (!(myrp = AllocMem(sizeof(struct RastPort),0))) return MEM_ERR;
  761.                 InitRastPort(myrp);
  762.                 SetFont(myrp,UserTextFont);
  763.                 rp = myrp;
  764.         }
  765.  
  766.         Font = &Attr;
  767.         OffX = Scr->WBorLeft;
  768.         OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;
  769.  
  770.         /* Get the tabsize from the taglist */
  771.         if (tag = FindTag(&Lay->LayTags, TABSIZE))
  772.                 TabSize = atoi(tag->Data);
  773.         else TabSize = DEFTABSIZE;
  774.  
  775.         AdjustVars(rp);
  776.         CalcPos(Lay, &GLim, ww, wh, rp); 
  777.         if (myrp) FreeMem(myrp, sizeof(struct RastPort));
  778.  
  779.         if ((*ww>Scr->Width || *wh>Scr->Height) && UserTextFont) { /* Try screen font */
  780.                 rp = &Scr->RastPort;
  781.                 AdjustVars(rp);
  782.                 CalcPos(Lay, &GLim, ww, wh, rp);
  783.         }
  784.                 
  785.         if (*ww > Scr->Width || *wh > Scr->Height) {    /* Try Topaz 8 */
  786.                 AdjustVars(NULL);
  787.                 CalcPos(Lay, &GLim, ww, wh, NULL); 
  788.                 if (*ww > Scr->Width || *wh > Scr->Height) return WINSIZE_ERR;
  789.         }
  790.         
  791.         /* Finally add GLim's offsets to all gadgets */
  792.         for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  793.                 vf->Pos.XOffset += OffX + FontX + GLim.XOffset;
  794.                 vf->Pos.YOffset += OffY + (FontY >> 1) + GLim.YOffset;
  795.         }
  796.  
  797.         /* Window specifics */
  798.         DB_Zoom[0] = 0;
  799.         DB_Zoom[1] = OffY;
  800.         DB_Zoom[2] =
  801.          TextLength( &Scr->RastPort, (UBYTE *)Pr->Name, strlen((char *)Pr->Name))
  802.          + TextLength( &Scr->RastPort, (UBYTE *)Lay->Name, strlen((char *)Lay->Name))
  803.          + FontX + 80;
  804.         DB_Zoom[3] = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
  805.         
  806.         /* Make sure window is not too small */
  807.         if (*ww < (DB_Zoom[2] + 8 * FontX)) *ww = DB_Zoom[2] + 8 * FontX;
  808.         if (*wh < DragKnobHeight * 5) {
  809.                 if (!Lay->FirstVisFldInfo) *wh = 10 * DragKnobHeight;
  810.                 else *wh = 5 * DragKnobHeight;
  811.         }
  812.         return 0;
  813. }
  814.  
  815. int CreateAllGadgets(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh, char mode)
  816. {
  817.         /* Create all gadgets with sizes, and positions fixed by CalcAllPos() */
  818.         struct FldInfo *f;
  819.         struct VisFldInfo *vf;
  820.         struct Gadget *g;
  821.         struct NewGadget ng;
  822.         struct RFFTag *tag;
  823.         struct RFFTag *sfmt; /* String format (left, right, center etc) */
  824.         LONG justification;     /* String format (left, right, center etc) */
  825.  
  826.         if (!(g = CreateContext(&Lay->GList))) return GAD_ERR;
  827.  
  828.         ng.ng_TextAttr = Font;
  829.         ng.ng_VisualInfo = VisualInfo;
  830.         ng.ng_UserData = 0;
  831.  
  832.         /* The drag gadget. (No dragbar in design mode) */
  833.         if (mode == USE_MODE) {
  834.                 ng.ng_GadgetText = NULL;
  835.                 ng.ng_GadgetID = SCROLLER_KIND; /* For our information, from gadtools.h */
  836.                 ng.ng_Flags = 0;
  837.  
  838.                 if (MyArgArray[HORIZBAR]) {
  839.                         ng.ng_LeftEdge = Scr->WBorLeft;
  840.                         ng.ng_TopEdge = wh - Scr->WBorBottom - DragKnobHeight;
  841.                         ng.ng_Width = ww - (Scr->WBorLeft + Scr->WBorRight);
  842.                         ng.ng_Height = DragKnobHeight;
  843.  
  844.                         Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
  845.                                 GTSC_Total, 1,
  846.                                 GTSC_Arrows, DragKnobWidth,
  847.                                 PGA_Freedom, LORIENT_HORIZ,
  848.                                 GA_Immediate, TRUE,
  849.                                 GA_RelVerify, TRUE,
  850.                                 TAG_DONE
  851.                         );
  852.                 }
  853.                 else {
  854.                         ng.ng_LeftEdge = ww - Scr->WBorRight - DragKnobWidth;
  855.                         ng.ng_TopEdge = OffY;
  856.                         ng.ng_Width = DragKnobWidth;
  857.                         ng.ng_Height = wh - OffY - Scr->WBorBottom;
  858.  
  859.                         Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
  860.                                 GTSC_Total, 1,
  861.                                 GTSC_Arrows, DragKnobHeight,
  862.                                 PGA_Freedom, LORIENT_VERT,
  863.                                 GA_Immediate, TRUE,
  864.                                 GA_RelVerify, TRUE,
  865.                                 TAG_DONE
  866.                         );
  867.                 }
  868.         } /* end-if RUN-MODE */
  869.  
  870.         /* The other gadgets */
  871.         for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
  872.  
  873.                 if (!(f = GetFldInfo(Pr, vf->Offset))) return RFF_ERR;
  874.  
  875.                 ng.ng_LeftEdge = vf->Pos.XOffset;
  876.                 ng.ng_TopEdge = vf->Pos.YOffset;
  877.                 ng.ng_Width = vf->Pos.Width;
  878.                 ng.ng_Height = vf->Pos.Height;
  879.                 ng.ng_GadgetText = vf->Name;
  880.  
  881.                 tag = SearchTag(CurrentPro, vf, NULL, PLACE);
  882.                 if (tag && !Stricmp(tag->Data, "above")) /* Title is above gadget */
  883.                         ng.ng_Flags = PLACETEXT_ABOVE;
  884.                 else ng.ng_Flags = PLACETEXT_LEFT;
  885.  
  886.                 if (MyArgArray[HIGHLABEL]) ng.ng_Flags |= NG_HIGHLABEL;
  887.  
  888.                 tag = SearchTag(CurrentPro, vf, NULL, FTYP);
  889.  
  890.                 if (tag && !Stricmp(tag->Data, "checkbox"))
  891.                 {
  892.                         Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
  893.                         ng.ng_Width = (ng.ng_Height * 3) >> 1;
  894.                         ng.ng_GadgetID = CHECKBOX_KIND; /* For our information, from gadtools.h */
  895.                         vf->Gadget = g = CreateGadget(CHECKBOX_KIND, g, &ng,
  896.                                 GT_Underscore, '_',
  897.                                 GTCB_Scaled, TRUE,
  898.                                 TAG_DONE
  899.                         );
  900.                 }
  901.                 else if (tag && !Stricmp(tag->Data, "cycle"))
  902.                 {
  903.                         Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
  904.                         ng.ng_GadgetID = CYCLE_KIND;    /* For our information, from gadtools.h */
  905.                         vf->Gadget = g = CreateGadget(CYCLE_KIND, g, &ng,
  906.                                 GT_Underscore, '_',
  907.                                 GTCY_Labels, vf->CEnt,
  908.                                 TAG_DONE
  909.                         );
  910.                 }
  911.                 else if (tag && !Stricmp(tag->Data, "text"))
  912.                 {
  913.                         Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
  914.                         ng.ng_GadgetID = TEXT_KIND;     /* For our information, from gadtools.h */
  915.                         justification = GTJ_LEFT;
  916.                         if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  917.                                 if (!Stricmp(sfmt->Data, "right")) justification = GTJ_RIGHT;
  918.                                 else if (!Stricmp(sfmt->Data, "center")) justification = GTJ_CENTER;
  919.                         }
  920.                         vf->Gadget = g = CreateGadget(TEXT_KIND, g, &ng,
  921.                                 GTTX_Justification, justification,
  922.                                 GT_Underscore, '_',
  923.                                 GTTX_Clipped, TRUE,
  924.                                 GTTX_Border, TRUE,
  925.                                 GTTX_CopyText, TRUE,
  926.                                 TAG_DONE
  927.                         );
  928.                 }
  929.                 else if (tag && !Stricmp(tag->Data, "textfield") && TextFieldClass) {
  930.                         long bordertype = TEXTFIELD_BORDER_DOUBLEBEVEL;
  931.  
  932.                         vf->Label.FrontPen = MyArgArray[HIGHLABEL] ? Pens[HIGHLIGHTTEXTPEN] : Pens[TEXTPEN];
  933.  
  934.                         Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
  935.                         if (MyArgArray[NOBORDER]) bordertype = TEXTFIELD_BORDER_NONE;
  936.                         justification = TEXTFIELD_ALIGN_LEFT;
  937.                         if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  938.                                 if (!Stricmp(sfmt->Data, "right")) justification = TEXTFIELD_ALIGN_RIGHT;
  939.                                 else if (!Stricmp(sfmt->Data, "center")) justification = TEXTFIELD_ALIGN_CENTER;
  940.                         }
  941.                         vf->Gadget = g = NewObject(TextFieldClass, NULL,
  942.                                                                         GA_ID,                          TEXTFIELD_KIND,
  943.                                                                         GA_Left,                                ng.ng_LeftEdge,
  944.                                                                         GA_Top,                         ng.ng_TopEdge,
  945.                                                                         GA_Width,                       ng.ng_Width,
  946.                                                                         GA_Height,                      ng.ng_Height,
  947.                                                                         GA_Previous,            g,
  948.                                                                         GA_TabCycle,            TRUE,
  949.                                                                         GA_IntuiText,           &vf->Label,
  950.                                                                         TEXTFIELD_ClipStream,   Iff0->iff_Stream,
  951.                                                                         TEXTFIELD_Border,                       bordertype,
  952.                                                                         TEXTFIELD_Alignment,            justification,
  953.                                                                         TEXTFIELD_MaxSize,              f->Len,
  954.                                                                         TEXTFIELD_TextAttr,             (ULONG)Font,
  955.                                                                         TEXTFIELD_BlockCursor,  TRUE,
  956.                                                                         TEXTFIELD_PassCommand,  TRUE,
  957.                                                                         TAG_END);
  958.                         vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
  959.                 }
  960.                 else {                  /* Assume string type as default */
  961.                         ng.ng_GadgetID = STRING_KIND;   /* For our information, from gadtools.h */
  962.  
  963.                         /* Handle string formatting */
  964.                         justification = STRINGLEFT;
  965.                         if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
  966.                                 if (!Stricmp(sfmt->Data, "right")) justification = STRINGRIGHT;
  967.                                 else if (!Stricmp(sfmt->Data, "center")) justification = STRINGCENTER;
  968.                         }
  969.                         
  970.                         vf->Gadget = g = CreateGadget(STRING_KIND, g, &ng,
  971.                                 STRINGA_ExitHelp, TRUE,
  972.                                 GTST_MaxChars, f->Len,
  973.                                 STRINGA_Justification, justification,
  974.                                 GT_Underscore, '_',
  975.                                 GTST_EditHook, &MyStrHook,
  976.                                 TAG_DONE
  977.                         );
  978.                         vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
  979.                 }                                                                                                                       /* GA_Immediate tag is v39  */
  980.         }
  981.  
  982.         if (Lay->FirstVisFldInfo) LastGad = Lay->FirstVisFldInfo->Gadget;
  983.         else LastGad = NULL;
  984.  
  985.         return 0;
  986. }
  987.  
  988. int AttachAllGadgets(struct Layout *Lay, WORD ww, WORD wh, char mode)
  989. {
  990.         /* Attach all gadgets to an already opened window, and size the window accordingly */
  991.         /* Use DoOpenLayWindow() instead if window is closed */
  992.  
  993.         struct IntuiMessage     *m;
  994.         ULONG class;
  995.         WORD clearw, clearh;    // Just so we don't clear more than neccesary.
  996.  
  997.         clearw = (Lay->Window->Width < ww) ? Lay->Window->Width : ww;
  998.         clearh = (Lay->Window->Height < wh) ? Lay->Window->Height : wh;
  999.  
  1000.         /* Resize (and maybe move) window */
  1001. //      Lay->Window->Flags |= WFLG_SIMPLE_REFRESH;      /* Speed */
  1002.         {
  1003.                 WORD x = (Lay->XPos >= 0) ? Lay->XPos : Lay->Window->LeftEdge;
  1004.                 WORD y = (Lay->YPos >= 0) ? Lay->YPos : Lay->Window->TopEdge;
  1005.                 ChangeWindowBox(Lay->Window, x, y, ww, wh);
  1006.         }
  1007.         /* The action is delayed until I get a IDCMP_NEWSIZE message. Ugly! */
  1008.         for (;;) {
  1009.                 WaitPort(Lay->Window->UserPort);
  1010.                 while( m = GT_GetIMsg( Lay->Window->UserPort )) {
  1011.                         class = m->Class;
  1012.                         GT_ReplyIMsg(m);
  1013.                         if (class == IDCMP_NEWSIZE) goto SIZEOK;
  1014.                 }
  1015.         }
  1016.         SIZEOK:
  1017. //      Lay->Window->Flags &= ~WFLG_SIMPLE_REFRESH;     /* Speed */
  1018.  
  1019.         if (mode == USE_MODE && MyArgArray[NOBORDER]) {
  1020.                 MyArgArray[NOSPEEDRENDER] = FALSE;
  1021.                 if (!SpeedRenderOn(Lay)) ByeBye();
  1022.         }
  1023.  
  1024.         AddGList(Lay->Window, Lay->GList, -1, -1, NULL);
  1025.  
  1026.         /* Clear old gadget imagery */
  1027.         EraseRect(Lay->Window->RPort, Lay->Window->BorderLeft, Lay->Window->BorderTop,
  1028.          clearw - Lay->Window->BorderRight-1, clearh - Lay->Window->BorderBottom-1);
  1029.  
  1030. //      RefreshWindowFrame(Lay->Window);
  1031.         RefreshGList(Lay->GList, Lay->Window, NULL, -1);
  1032.         GT_RefreshWindow( Lay->Window, NULL ); /* Must also be called. Works fine without however */
  1033.  
  1034.         if (mode == DESIGN_MODE)
  1035.                 RemoveGList(Lay->Window, Lay->GList, -1);
  1036.  
  1037.         else if (!MyArgArray[NOBORDER])
  1038.                 if (!SpeedRenderOn(Lay)) ByeBye();
  1039.  
  1040.         return 0;
  1041. }
  1042.  
  1043.  
  1044. int DoOpenLayWindow(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh)
  1045. {
  1046.         /* Does the actual opening (in USE_MODE) */
  1047.         WORD leftedge, topedge;
  1048.  
  1049.         if (MyArgArray[NOBORDER]) {
  1050.                 MyArgArray[NOSPEEDRENDER] = FALSE;
  1051.                 if (!SpeedRenderOn(Lay)) ByeBye();
  1052.         }
  1053.  
  1054.         /* Position window nicely */
  1055.         if (LastLeftEdge == -1) {       /* No previous window to use */
  1056.                 leftedge = (Scr->Width - ww) >> 1;      /* Middle */
  1057.                 topedge = (Scr->Height - wh) >> 1;      /* Middle */
  1058.         }
  1059.         else {
  1060.                 leftedge = LastLeftEdge;
  1061.                 topedge = LastTopEdge;
  1062.         }
  1063.         if (Lay->XPos != -1) leftedge = Lay->XPos;
  1064.         if (Lay->YPos != -1)    topedge = Lay->YPos;
  1065.  
  1066.         if ( ! ( Lay->Window = OpenWindowTags( NULL,
  1067.                                 WA_Left,           leftedge,
  1068.                                 WA_Top,         topedge,
  1069.                                 WA_Width,       ww,
  1070.                                 WA_Height,      wh,
  1071.                                 WA_IDCMP,       STRINGIDCMP|SCROLLERIDCMP|ARROWIDCMP|IDCMP_NEWSIZE|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_MENUHELP|IDCMP_REFRESHWINDOW,
  1072.                                 WA_Flags,       WFLG_NEWLOOKMENUS|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
  1073.                                 WA_Gadgets,     Lay->GList,
  1074.                                 WA_Title,       Lay->Title,
  1075.                                 WA_ScreenTitle, "db v" VERSION_NUMBER "  ©1997-1998 David Ekholm, Marcin Orlowski",
  1076.                                 WA_PubScreen,   Scr,
  1077.                                 WA_Zoom,        DB_Zoom,
  1078.                                 WA_MenuHelp, TRUE,
  1079.                                 TAG_DONE )))
  1080.         return WIN_ERR;
  1081.  
  1082.         if (!Pr->Menu) OpenMenu(Pr);
  1083.         SetMenuStrip(Lay->Window, Pr->Menu);
  1084.  
  1085.         GT_RefreshWindow( Lay->Window, NULL);
  1086.         /* AppWindow specifics */
  1087.         Lay->AppWin = AddAppWindow(1, 1, Lay->Window, AWPort, NULL);
  1088.         /* End of AppWindow specifics */
  1089.  
  1090.         /* We delete the reference to the gadget borders to double the update speed */
  1091.         /* We relink the information before windowclosing so that memory is freed */
  1092.         if (!MyArgArray[NOBORDER])
  1093.                 if (!SpeedRenderOn(Lay)) ByeBye();
  1094.  
  1095.         /* For IDCMP handling used in this file and in main() */
  1096.         WinSig = 1L << Lay->Window->UserPort->mp_SigBit;
  1097.  
  1098.         return 0;
  1099. }
  1100.  
  1101.  
  1102. int OpenLayWin(struct Pro *Pr, struct Layout *Lay)
  1103. {
  1104.         /* Frontend function for the old db code */
  1105.         int ret;
  1106.         WORD ww, wh; /* Final window width and height */
  1107.         
  1108.         if ((ret = CalcAllPos(Pr, Lay, &ww, &wh)) < 0) return ret;
  1109.         if ((ret = CreateAllGadgets(Pr, Lay, ww, wh, USE_MODE)) < 0) return ret;
  1110.         if ((ret = DoOpenLayWindow(Pr, Lay, ww, wh)) < 0) return ret;
  1111.         return 0;
  1112. }
  1113.